import { _decorator, CCInteger, Component, instantiate, Label, Node, Prefab, Vec3 } from 'cc';
import { BLOCK_SIZE, PlayerController } from './PlayerController';
const { ccclass, property } = _decorator;

// 用 BT_NONE 来表示坑，而 BT_STONE 来表示方块
enum BlockType{
    BT_NONE,
    BT_STONE,
};
// 游戏有三种状态，初始化、游戏中、游戏重置或者结算，和下棋类似，大部分游戏都可以粗略分解为这样的三个状态
enum GameState{
    GS_INIT,
    GS_PLAYING,
    GS_END,
};

@ccclass('GameManager')
export class GameManager extends Component {

    @property({type: Prefab})
    public boxPrefab: Prefab|null = null;
    @property({type: CCInteger})
    public roadLength: number = 50;
    private _road: BlockType[] = [];
    @property({ type: Node })
    public startMenu: Node | null = null; // 开始的 UI
    @property({ type: PlayerController }) 
    public playerCtrl: PlayerController | null = null; // 角色控制器
    @property({type: Label}) 
    public stepsLabel: Label|null = null; // 计步器
    
    start() {
        this.setCurState(GameState.GS_INIT); // 第一初始化要在 start 里面调用
        this.playerCtrl?.node.on('JumpEnd', this.onPlayerJumpEnd, this); // 添加监听事件 这里我们使用的 this.playerCtrl?.node 也就是 PlayerController 的节点来接收事件 因为 某个节点派发的事件，只能用这个节点的引用去监听
    }

    // 处理状态
    setCurState (value: GameState) {
        switch(value) {
            case GameState.GS_INIT:
                // GS_INIT：状态下需要初始化地图、将角色放回到初始点、显示游戏的UI
                this.init();         
                break;
            case GameState.GS_PLAYING:
                // GS_PLAYING：在状态下隐藏 StartMenu、重设计步器的数值以及启用用户输入
                this.playing();
                break;
            case GameState.GS_END:
                break;
        }
    }

    // 初始方法
    init () {
        if (this.startMenu) {
            this.startMenu.active = true;
        }
        this.generateRoad()
        if (this.playerCtrl) {
            this.playerCtrl.setInputActive(false);
            this.playerCtrl.node.setPosition(Vec3.ZERO);
            this.playerCtrl.reset();
        }
    }

    playing () {
        if (this.startMenu) {
            this.startMenu.active = false;
        }
      
        if (this.stepsLabel) {
            this.stepsLabel.string = '0';   // 将步数重置为0
        }
      
        setTimeout(() => {      //直接设置active会直接开始监听鼠标事件，做了一下延迟处理
            if (this.playerCtrl) {
                this.playerCtrl.setInputActive(true);
            }
        }, 0.1);
    }

    // 用于响应 Play 按钮按下的事件
    onStartButtonClicked() {
        this.setCurState(GameState.GS_PLAYING);
    }

    generateRoad() {

        this.node.removeAllChildren();
  
        this._road = [];
        // startPos
        this._road.push(BlockType.BT_STONE);
        for (let i = 1; i < this.roadLength; i++) {
            if (this._road[i - 1] === BlockType.BT_NONE) {
                this._road.push(BlockType.BT_STONE);
            } else {
                this._road.push(Math.floor(Math.random() * 2));
            }
        }
  
        for (let j = 0; j < this._road.length; j++) {
            let block: Node | null = this.spawnBlockByType(this._road[j]);
            if (block) {
                this.node.addChild(block);
                block.setPosition(j * BLOCK_SIZE, 0, 0);
            }
        }
    }

    spawnBlockByType(type: BlockType) {
        if (!this.boxPrefab) {
            return null;
        }
  
        let block: Node|null = null;
        switch(type) {
            case BlockType.BT_STONE:
                block = instantiate(this.boxPrefab);
                break;
        }
  
        return block;
    }

    // 判定角色是否跳跃到坑或者跳完所有地块
    checkResult(moveIndex: number) {
        if (moveIndex < this.roadLength) {
            if (this._road[moveIndex] == BlockType.BT_NONE) {   //跳到了空方块上
                this.setCurState(GameState.GS_INIT)
            }
        } else {
            // 跳过了最大长度    
            this.setCurState(GameState.GS_INIT);
        }
    }

    // 跳跃结束的方法
    onPlayerJumpEnd(moveIndex: number) {
        console.log(moveIndex)
        // 更新的计步器并检查角色是调到坑里面还是跳所有的方块，如果满足这两个条件，则重置整个游戏逻辑
        if (this.stepsLabel) {
            this.stepsLabel.string = '' + (moveIndex >= this.roadLength ? this.roadLength : moveIndex);
        }
        this.checkResult(moveIndex);
    }

    update(deltaTime: number) {
        
    }
}

